﻿using System;
using System.Collections.Generic;
using AFS.VisitationRequestTool.Addin.Wrappers;
using AFS.VisitationRequestTool.Addin.Entities;
using Outlook = Microsoft.Office.Interop.Outlook;
using AFS.VisitationRequestTool.Addin.Common;

namespace AFS.VisitationRequestTool.Addin
{
    /// <summary>
    /// The AddIn controller essentially.
    /// </summary>
    public partial class ThisAddIn
    {
        /// <summary>
        /// Holds a reference to the Application.Inspectors collection
        /// Required to get notifications for NewInspector events.
        /// </summary>
        private Outlook.Inspectors inspectors;

        /// <summary>
        /// A dictionary that holds a reference to the Inspectors handled by the add-in
        /// </summary>
        private Dictionary<Guid, InspectorWrapper> wrappedInspectors;

        /// <summary>
        /// Startup method is called when the add-in is loaded by Outlook
        /// </summary>
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            wrappedInspectors = new Dictionary<Guid, InspectorWrapper>();
            inspectors = Globals.ThisAddIn.Application.Inspectors;
            inspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler(WrapInspector);

            // Handle also already existing Inspectors
            // (e.g. Double clicking a .msg file)
            foreach (Outlook.Inspector inspector in inspectors)
            {
                WrapInspector(inspector);
            }
        }

        /// <summary>
        /// Wraps an Inspector if required, then stores Inspector in memory to get future events fired by the wrapped Inspector
        /// </summary>
        /// <param name="inspector">The Outlook Inspector instance</param>
        void WrapInspector(Outlook.Inspector inspector)
        {
            InspectorWrapper wrapper = InspectorWrapper.GetWrapperFor(inspector);
            if (wrapper != null)
            {
                // register for the closed event
                wrapper.Closed += new InspectorWrapperClosedEventHandler(Wrapper_Closed);
                // remember the inspector in memory
                wrappedInspectors[wrapper.Id] = wrapper;
            }

            // Resetting loaded flags that are used to handle misfiring of form load and ribbon load events in certain clients
            //Globals.RibbonLoaded = false;
            //Globals.FormRegionLoaded = false;
        }

        /// <summary>
        /// Method is called when an inspector has been closed
        /// Removes reference from memory
        /// </summary>
        /// <param name="id">The unique id of the closed inspector</param>
        void Wrapper_Closed(Guid id)
        {
            wrappedInspectors.Remove(id);
        }

        /// <summary>
        /// Shutdown method is called when Outlook is unloading the add-in
        /// </summary>
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            // do the homework and cleanup
            wrappedInspectors.Clear(); // NOTE: Clear() actually holds a weak reference.
            inspectors.NewInspector -= new Outlook.InspectorsEvents_NewInspectorEventHandler(WrapInspector);
            inspectors = null;
            GC.Collect(); // NOTE: Why are we explicitly calilng the GC to collect?  Shouldn't we let it do it's job since this can be an expensive process CPU wise.
            GC.WaitForPendingFinalizers(); // NOTE: I suppose blocking makes sense here since we're shutting down.
        }

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);

        }

        #endregion
    }


    internal sealed partial class Globals
    {
        //private static SessionContext session = SessionContext.Instance;

        //public static SessionContext SessionContext
        //{
        //    get
        //    {
        //        return session;
        //    }
        //}

        private static bool formRegionLoaded;

        public static bool FormRegionLoaded
        {
            get { return formRegionLoaded; }
            set { formRegionLoaded = value; }
        }

        private static bool ribbonLoaded;

        public static bool RibbonLoaded
        {
            get { return ribbonLoaded; }
            set { ribbonLoaded = value; }
        }

    }
}
